home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Scene 96
/
Scene 96 International Edition (Zyklop Software) (Disc 2) (1997).iso
/
misc
/
coding
/
cp2dekit
/
samples
/
devwgus.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1996-12-29
|
34KB
|
1,702 lines
//***************************************************************************
//
// this file is (c) '94-'96 Niklas Beisert
//
// this file is part of the cubic player development kit.
// you may only use/modify/spread this file under the terms stated
// in the cubic player development kit accompanying documentation.
//
//***************************************************************************
//[sound]
// playerdevices=devpWSS devpGUS devpSB devpPAS devpNone devpDisk
//[devwGUS]
// link=devwgus
// driver=_mcpUltraSound
// addprocs=_mcpGUSAdd
// handle=2
// gusSlowUpload=on
// gusSystemTimer=on
// wavetable device example
#include <time.h>
#include <string.h>
#include <conio.h>
#include <stdlib.h>
#include <ctype.h>
#include "ss.h"
#include "mcp.h"
#include "mix.h"
#include "irq.h"
#include "dma.h"
#include "timer.h"
#define MAXSAMPLES 256
#define SS_GUS_SLOWUPLOAD 1
#define SS_GUS_SYSTIMER 2
extern "C" extern sounddevice mcpUltraSound;
static unsigned short gusPort;
static unsigned char gusDMA;
static unsigned char gusIRQ;
static unsigned char gusDMA2;
static unsigned char gusIRQ2;
static unsigned long gusMem;
static unsigned char activevoices;
unsigned long muldiv64(unsigned long, unsigned long, unsigned long);
//#pragma aux muldiv64 parm [eax] [edx] [ecx] = "mul edx" "div ecx"
#pragma aux muldiv64 parm [eax] [edx] [ecx] modify [ebx] = "mul edx" "mov ebx,ecx" "shr ebx,1" "add eax,ebx" "adc edx,0" "div ecx"
static char getcfg()
{
char *ptr=getenv("ULTRASND");
if (!ptr)
return 0;
while (isspace(*ptr))
ptr++;
if (!ptr)
return 0;
gusPort=strtoul(ptr, 0, 16);
while ((*ptr!=',')&&*ptr)
ptr++;
if (!*ptr++)
return 0;
gusDMA=strtoul(ptr, 0, 10)&7;
while ((*ptr!=',')&&*ptr)
ptr++;
if (!*ptr++)
return 0;
gusDMA2=strtoul(ptr, 0, 10)&7;
while ((*ptr!=',')&&*ptr)
ptr++;
if (!*ptr++)
return 0;
gusIRQ=strtoul(ptr, 0, 10)&15;
while ((*ptr!=',')&&*ptr)
ptr++;
if (!*ptr++)
return 0;
gusIRQ2=strtoul(ptr, 0, 10)&15;
return 1;
}
static unsigned char inpGUS(unsigned short p)
{
return inp(gusPort+p);
}
static unsigned short inpwGUS(unsigned short p)
{
return inpw(gusPort+p);
}
static void delayGUS()
{
inp(gusPort+0x107);
inp(gusPort+0x107);
inp(gusPort+0x107);
inp(gusPort+0x107);
inp(gusPort+0x107);
inp(gusPort+0x107);
inp(gusPort+0x107);
inp(gusPort+0x107);
}
static void outpGUS(unsigned short p, unsigned char v)
{
outp(gusPort+p,v);
}
static void outpwGUS(unsigned short p, unsigned short v)
{
outpw(gusPort+p,v);
}
static void outGUS(unsigned char c, unsigned char v)
{
outp(gusPort+0x103, c);
outp(gusPort+0x105, v);
}
static void outdGUS(unsigned char c, unsigned char v)
{
outp(gusPort+0x103, c);
outp(gusPort+0x105, v);
delayGUS();
outp(gusPort+0x105, v);
}
static void outwGUS(unsigned char c, unsigned short v)
{
outp(gusPort+0x103, c);
outpw(gusPort+0x104, v);
}
static unsigned char inGUS(unsigned char c)
{
outp(gusPort+0x103, c);
return inp(gusPort+0x105);
}
static unsigned short inwGUS(unsigned char c)
{
outp(gusPort+0x103, c);
return inpw(gusPort+0x104);
}
static inline void outpGUS0(unsigned char v)
{
outpGUS(0x00, v);
}
static inline void outpGUS8(unsigned char v)
{
outpGUS(0x08, v);
}
static inline void outpGUS9(unsigned char v)
{
outpGUS(0x09, v);
}
static inline void outpGUSB(unsigned char v)
{
outpGUS(0x0B, v);
}
static inline void outpGUSF(unsigned char v)
{
outpGUS(0x0F, v);
}
static inline unsigned char peekGUS(unsigned long adr)
{
outwGUS(0x43, adr);
outdGUS(0x44, adr>>16);
return inpGUS(0x107);
}
static inline void pokeGUS(unsigned long adr, unsigned char data)
{
outwGUS(0x43, adr);
outdGUS(0x44, adr>>16);
outpGUS(0x107, data);
}
static inline void selvoc(char ch)
{
outpGUS(0x102, ch);
}
static inline void setfreq(unsigned short frq)
{
outwGUS(0x01, frq&~1);
}
static inline void setvol(unsigned short vol)
{
outwGUS(0x09, vol<<4);
}
static inline unsigned short getvol()
{
return inwGUS(0x89)>>4;
}
static inline void setpan(unsigned char pan)
{
outGUS(0x0C, pan);
}
static inline void setpoint8(unsigned long p, unsigned char t)
{
t=(t==1)?0x02:(t==2)?0x04:0x0A;
outwGUS(t, (p>>7)&0x1FFF);
outwGUS(t+1, p<<9);
}
static inline unsigned long getpoint8(unsigned char t)
{
t=(t==1)?0x82:(t==2)?0x84:0x8A;
return (inwGUS(t)<<16)|inwGUS(t+1);
}
static inline void setmode(unsigned char m)
{
outdGUS(0x00, m);
}
static inline unsigned char getmode()
{
return inGUS(0x80);
}
static inline void setvst(unsigned char s)
{
outGUS(0x07, s);
}
static inline void setvend(unsigned char s)
{
outGUS(0x08, s);
}
static inline void setvmode(unsigned char m)
{
outdGUS(0x0D, m);
}
static inline unsigned char getvmode()
{
return inGUS(0x8D);
}
static inline void settimer(unsigned char o)
{
outGUS(0x45, o);
}
static inline void settimerlen(unsigned char l)
{
outGUS(0x46, l);
}
static int testPort(unsigned short port)
{
gusPort=port;
outGUS(0x4C, 0);
delayGUS();
delayGUS();
outGUS(0x4C, 1);
delayGUS();
delayGUS();
char v0=peekGUS(0);
char v1=peekGUS(1);
pokeGUS(0,0xAA);
pokeGUS(1,0x55);
char gus=peekGUS(0)==0xAA;
pokeGUS(0,v0);
pokeGUS(1,v1);
if (!gus)
return 0;
int i,j;
unsigned char oldmem[4];
for (i=0; i<4; i++)
oldmem[i]=peekGUS(i*256*1024);
pokeGUS(0,1);
pokeGUS(0,1);
gusMem=256*1024;
for (i=1; i<4; i++)
{
pokeGUS(i*256*1024, 15+i);
pokeGUS(i*256*1024, 15+i);
for (j=0; j<i; j++)
{
if (peekGUS(j*256*1024)!=(1+j))
break;
if (peekGUS(j*256*1024)!=(1+j))
break;
}
if (j!=i)
break;
if (peekGUS(i*256*1024)!=(15+i))
break;
if (peekGUS(i*256*1024)!=(15+i))
break;
pokeGUS(i*256*1024, 1+i);
pokeGUS(i*256*1024, 1+i);
gusMem+=256*1024;
}
for (i=3; i>=0; i--)
{
pokeGUS(i*256*1024, oldmem[i]);
pokeGUS(i*256*1024, oldmem[i]);
}
return 1;
}
static void initgus(char voices)
{
if (voices<14)
voices=14;
if (voices>32)
voices=32;
activevoices=voices;
int i;
outGUS(0x4C, 0);
for (i=0; i<10; i++)
delayGUS();
outGUS(0x4C, 1);
for (i=0; i<10; i++)
delayGUS();
outGUS(0x41, 0x00);
outGUS(0x45, 0x00);
outGUS(0x49, 0x00);
outGUS(0xE, (voices-1)|0xC0);
inpGUS(0x6);
inGUS(0x41);
inGUS(0x49);
inGUS(0x8F);
for (i=0; i<32; i++)
{
selvoc(i);
setvol(0); // vol=0
setmode(3); // stop voice
setvmode(3); // stop volume
setpoint8(0,0);
outGUS(0x06, 63);
delayGUS();
}
inpGUS(0x6);
inGUS(0x41);
inGUS(0x49);
inGUS(0x8F);
outGUS(0x4C,0x07);
/*
unsigned char l1="\x00\x00\x01\x03\x00\x02\x00\x04\x00\x00\x00\x05\x06\x00\x00\x07"[gusIRQ]|((gusIRQ==gusIRQ2)?0x40:"\x00\x00\x08\x18\x00\x10\x00\x20\x00\x00\x00\x28\x30\x00\x00\x38"[gusIRQ2]);
unsigned char l2="\x00\x01\x00\x02\x00\x03\x04\x05"[gusDMA]|((gusDMA==gusDMA2)?0x40:"\x00\x08\x00\x10\x00\x18\x20\x28"[gusDMA2]);
outpGUSF(5);
outpGUS0(0x0B);
outpGUSB(0);
outpGUSF(0);
outpGUS0(0x0B);
outpGUSB(l2|0x80);
outpGUS0(0x4B);
outpGUSB(l1);
outpGUS0(0x0B);
outpGUSB(l2);
outpGUS0(0x4B);
outpGUSB(l1);
*/
selvoc(0);
outpGUS0(0x08);
selvoc(0);
/*
outGUS(0x4C,0x01);
settimer(0x00); // stop timer
outpGUS8(0x04);
outpGUS9(0x80);
*/
}
struct guschan
{
unsigned long startpos;
unsigned long endpos;
unsigned long loopstart;
unsigned long loopend;
unsigned long samprate;
unsigned char redlev;
unsigned short cursamp;
unsigned char mode;
unsigned short voll;
unsigned short volr;
unsigned char inited;
signed char chstatus;
signed short nextsample;
signed long nextpos;
unsigned char orgloop;
signed char loopchange;
unsigned long orgfreq;
unsigned long orgdiv;
unsigned short orgvol;
signed short orgpan;
unsigned char pause;
unsigned char wasplaying;
void *smpptr;
};
struct gussample
{
signed long pos;
unsigned long length;
unsigned long loopstart;
unsigned long loopend;
unsigned long samprate;
int type;
unsigned char redlev;
void *ptr;
};
static unsigned short linvol[513];
static unsigned long mempos;
static gussample samples[MAXSAMPLES];
static unsigned short samplenum;
static unsigned char channelnum;
static void (*playerproc)();
static guschan channels[32];
static unsigned long gtimerlen;
static unsigned long gtimerpos;
static unsigned long stimerlen;
static unsigned long stimerpos;
static char __far *stack;
static const unsigned long stacksize=8192;
static unsigned char stackused;
static void __far *oldssesp;
static unsigned short relspeed;
static unsigned long orgspeed;
static unsigned char mastervol;
static signed char masterpan;
static signed char masterbal;
static unsigned short masterfreq;
static unsigned long amplify;
static unsigned char paused;
static unsigned char doublechan;
static __segment dmasel;
static void *dmabuf;
static int dmalen;
static volatile unsigned char dmaactive;
static void *dmaxfer;
static unsigned long dmaleft;
static unsigned long dmapos;
static unsigned char dma16bit;
static unsigned char doslowupload;
static unsigned char usesystimer;
static unsigned char filter;
static void fadevol(unsigned short v)
{
unsigned short start=getvol();
unsigned short end=v;
unsigned char vmode;
if (abs((short)(start-end))<64)
{
setvol(end);
return;
}
if (start>end)
{
unsigned short t=start;
start=end;
end=t;
vmode=0x40;
}
else
vmode=0;
if (start<64)
start=64;
if (end>4032)
end=4032;
setvst(start>>4);
setvend(end>>4);
setvmode(vmode);
}
static inline void fadevoldown()
{
setvst(0x04);
setvend(0xFC);
setvmode(0x40);
}
static void processtick()
{
int i;
for (i=0; i<channelnum; i++)
{
guschan &c=channels[i];
if (c.inited&&(c.chstatus||(c.nextpos!=-1)))
{
selvoc(i);
setmode(c.mode|3);
fadevoldown();
}
c.chstatus=0;
}
for (i=0; i<channelnum; i++)
{
selvoc(i);
while (!(getvmode()&1));
}
for (i=0; i<channelnum; i++)
{
guschan &c=channels[i];
selvoc(i);
if (c.inited)
{
if (c.nextsample!=-1)
{
gussample &s=samples[c.nextsample];
unsigned char bit16=!!(s.type&mcpSamp16Bit);
c.startpos=s.pos;
if (bit16)
c.startpos=(c.startpos&0xC0000)|((c.startpos>>1)&0x1FFFF)|0x20000;
c.endpos=c.startpos+s.length;
c.loopstart=c.startpos+s.loopstart;
c.loopend=c.startpos+s.loopend;
c.samprate=s.samprate;
c.redlev=s.redlev;
c.smpptr=s.ptr;
c.mode=0;
if (bit16)
c.mode|=0x04;
c.cursamp=c.nextsample;
c.orgloop=0;
if (s.type&mcpSampLoop)
{
c.orgloop=1;
c.mode|=0x08;
if (s.type&mcpSampBiDi)
c.mode|=0x10;
setpoint8(c.loopstart, 1);
setpoint8(c.loopend, 2);
}
else
{
setpoint8(c.startpos, 1);
setpoint8(c.endpos, 2);
}
}
if (c.nextpos!=-1)
{
unsigned long pos=c.startpos+(c.nextpos>>c.redlev);
if (c.mode&0x08)
{
if (pos>=c.loopend)
pos=c.loopstart+(pos-c.loopstart)%(c.loopend-c.loopstart);
}
else
if (pos>=c.endpos)
pos=c.endpos-1;
setpoint8(pos, 0);
setmode(c.mode|(getmode()&0x40));
}
if (c.loopchange!=-1)
{
if (c.loopchange&&c.orgloop)
c.mode|=0x08;
else
c.mode&=~0x08;
setmode(c.mode|(getmode()&0x40));
if (c.mode&0x08)
{
setpoint8(c.loopstart, 1);
setpoint8(c.loopend, 2);
}
else
{
setpoint8(c.startpos, 1);
setpoint8(c.endpos, 2);
}
}
if (!(getmode()&1))
{
short v,p;
v=c.voll+c.volr;
if (v)
setpan((15*c.volr+v/2)/v);
fadevol(c.pause?0:linvol[v]);
setfreq(muldiv64(muldiv64(c.orgfreq, c.samprate*masterfreq, c.orgdiv), activevoices, 154350));
}
else
fadevoldown();
}
else
fadevoldown();
c.nextsample=-1;
c.nextpos=-1;
c.loopchange=-1;
}
playerproc();
stimerlen=muldiv64(256, 1193046*256, orgspeed*relspeed);
gtimerlen=muldiv64(256, 12500*256, orgspeed*relspeed);
}
static void processtickdc()
{
int i;
for (i=0; i<channelnum; i++)
{
guschan &c=channels[i];
if (c.inited&&(c.chstatus||(c.nextpos!=-1)))
{
selvoc(2*i);
setmode(c.mode|3);
fadevoldown();
selvoc(2*i+1);
setmode(c.mode|3);
fadevoldown();
}
c.chstatus=0;
}
for (i=0; i<channelnum; i++)
{
selvoc(2*i);
while (!(getvmode()&1));
selvoc(2*i+1);
while (!(getvmode()&1));
}
for (i=0; i<channelnum; i++)
{
guschan &c=channels[i];
if (c.inited)
{
if (c.nextsample!=-1)
{
gussample &s=samples[c.nextsample];
unsigned char bit16=!!(s.type&mcpSamp16Bit);
c.startpos=s.pos;
if (bit16)
c.startpos=(c.startpos&0xC0000)|((c.startpos>>1)&0x1FFFF)|0x20000;
c.endpos=c.startpos+s.length;
c.loopstart=c.startpos+s.loopstart;
c.loopend=c.startpos+s.loopend;
c.samprate=s.samprate;
c.redlev=s.redlev;
c.smpptr=s.ptr;
c.mode=0;
if (bit16)
c.mode|=0x04;
c.cursamp=c.nextsample;
c.orgloop=0;
if (s.type&mcpSampLoop)
{
c.orgloop=1;
c.mode|=0x08;
if (s.type&mcpSampBiDi)
c.mode|=0x10;
selvoc(2*i);
setpoint8(c.loopstart, 1);
setpoint8(c.loopend, 2);
selvoc(2*i+1);
setpoint8(c.loopstart, 1);
setpoint8(c.loopend, 2);
}
else
{
selvoc(2*i);
setpoint8(c.startpos, 1);
setpoint8(c.endpos, 2);
selvoc(2*i+1);
setpoint8(c.startpos, 1);
setpoint8(c.endpos, 2);
}
}
if (c.nextpos!=-1)
{
unsigned long pos=c.startpos+(c.nextpos>>c.redlev);
if (c.mode&0x08)
{
if (pos>=c.loopend)
pos=c.loopstart+(pos-c.loopstart)%(c.loopend-c.loopstart);
}
else
if (pos>=c.endpos)
pos=c.endpos;
selvoc(2*i);
setpoint8(pos, 0);
selvoc(2*i+1);
setpoint8(pos, 0);
selvoc(2*i);
setmode(c.mode|(getmode()&0x40));
selvoc(2*i+1);
setmode(c.mode|(getmode()&0x40));
}
if (c.loopchange!=-1)
{
if (c.loopchange&&c.orgloop)
c.mode|=0x08;
else
c.mode&=~0x08;
selvoc(2*i);
setmode(c.mode|(getmode()&0x40));
if (c.mode&0x08)
{
setpoint8(c.loopstart, 1);
setpoint8(c.loopend, 2);
}
else
{
setpoint8(c.startpos, 1);
setpoint8(c.endpos, 2);
}
selvoc(2*i+1);
setmode(c.mode|(getmode()&0x40));
if (c.mode&0x08)
{
setpoint8(c.loopstart, 1);
setpoint8(c.loopend, 2);
}
else
{
setpoint8(c.startpos, 1);
setpoint8(c.endpos, 2);
}
}
selvoc(2*i);
if (!(getmode()&1))
{
unsigned long frq=muldiv64(muldiv64(c.orgfreq, c.samprate*masterfreq, c.orgdiv), activevoices, 154350);
selvoc(2*i);
setfreq(frq);
fadevol(c.pause?0:linvol[c.voll]);
selvoc(2*i+1);
setfreq(frq);
fadevol(c.pause?0:linvol[c.volr]);
}
else
{
selvoc(2*i);
fadevoldown();
selvoc(2*i+1);
fadevoldown();
}
}
else
{
selvoc(2*i);
fadevoldown();
selvoc(2*i+1);
fadevoldown();
}
c.nextsample=-1;
c.nextpos=-1;
c.loopchange=-1;
}
playerproc();
stimerlen=muldiv64(256, 1193046*256, orgspeed*relspeed);
gtimerlen=muldiv64(256, 12500*256, orgspeed*relspeed);
}
unsigned long doupload8(const void *buf, unsigned long guspos, unsigned long maxlen, unsigned short port);
#pragma aux doupload8 parm [esi] [ebx] [ecx] [edx] modify [eax] value [ebx] = \
"pushf" \
"cli" \
"add dx,103h" \
"mov al,44h" \
"out dx,al" \
"add dx,2" \
"mov eax,ebx" \
"shr eax,16" \
"out dx,al" \
"sub dx,2" \
"mov al,43h" \
"out dx,al" \
"inc dx" \
"lp:" \
"mov ax,bx" \
"out dx,ax" \
"mov al,[esi]" \
"add dx,3" \
"out dx,al" \
"sub dx,3" \
"inc ebx" \
"inc esi" \
"test bl,bl" \
"loopnz lp" \
"popf"
unsigned long doupload16(const void *buf, unsigned long guspos, unsigned long maxlen, unsigned short port);
#pragma aux doupload16 parm [esi] [ebx] [ecx] [edx] modify [eax] value [ebx] = \
"pushf" \
"cli" \
"add dx,103h" \
"mov al,44h" \
"out dx,al" \
"add dx,2" \
"mov eax,ebx" \
"shr eax,16" \
"out dx,al" \
"sub dx,2" \
"mov al,43h" \
"out dx,al" \
"inc dx" \
"shr ecx,1" \
"lp:" \
"mov ax,bx" \
"out dx,ax" \
"mov al,[esi]" \
"add dx,3" \
"out dx,al" \
"sub dx,3" \
"inc ebx" \
"mov ax,bx" \
"out dx,ax" \
"mov al,[esi+1]" \
"add dx,3" \
"out dx,al" \
"sub dx,3" \
"inc ebx" \
"add esi,2" \
"test bl,bl" \
"loopnz lp" \
"popf"
static void dmaupload()
{
int upbytes;
if (dmapos&31)
{
upbytes=(-dmapos)&31;
if (upbytes>dmaleft)
upbytes=dmaleft;
if (!dma16bit)
doupload8(dmaxfer, dmapos, upbytes, gusPort);
else
doupload16(dmaxfer, dmapos, upbytes, gusPort);
dmaxfer=((char*)dmaxfer)+upbytes;
dmaleft-=upbytes;
dmapos+=upbytes;
}
if (!dmaleft)
{
dmaactive=0;
return;
}
upbytes=dmaleft;
if (upbytes>dmalen)
upbytes=dmalen;
if (((dmapos+upbytes)&0xC0000)>(dmapos&0xC0000))
upbytes=0x40000-(dmapos&0x3FFFF);
dmaactive=1;
unsigned short adr=dmapos>>4;
if (gusDMA&4)
adr=(adr&0xC000)|((adr&0x3FFF)>>1);
outGUS(0x41, 0);
memcpy(dmabuf, dmaxfer, upbytes);
dmaStart(gusDMA, dmabuf, upbytes, 0x08);
dmaxfer=((char*)dmaxfer)+upbytes;
dmaleft-=upbytes;
dmapos+=upbytes;
outwGUS(0x42, adr);
outGUS(0x41, (gusDMA&4)|0x21|(dma16bit?0x40:0x00));
}
static void slowupload()
{
unsigned long endpos=dmapos+dmaleft;
unsigned long stpos=dmapos;
if (!dma16bit)
while (dmapos<endpos)
dmapos=doupload8((char*)dmaxfer+dmapos-stpos, dmapos, endpos-dmapos, gusPort);
else
while (dmapos<endpos)
dmapos=doupload16((char*)dmaxfer+dmapos-stpos, dmapos, endpos-dmapos, gusPort);
}
static void handle_voice()
{
/*
unsigned long wave_ignore=0;
unsigned long volume_ignore=0;
while (1)
{
unsigned char irq_source=inGUS(0x8F);
unsigned char voice=irq_source&0x1F;
if ((irq_source&0xC0)==0xC0)
break;
unsigned long voice_bit=1<<voice;
if (!(irq_source&0x80))
if (!(wave_ignore&voice_bit))
{
selvoc(voice);
if (!((inGUS(0x80)&0x08)||(inGUS(0x8D)&0x04)))
wave_ignore|=voice_bit;
}
if (!(irq_source&0x40))
if (!(volume_ignore&voice_bit))
{
selvoc(voice);
if (!(inGUS(0x8D)&0x08))
volume_ignore|=voice_bit;
}
}
*/
}
static void irqrout()
{
while (1)
{
unsigned char source=inpGUS(0x6);
if (!source)
break;
if (source&0x03)
inpGUS(0x100);
if (source&0x80)
if (inGUS(0x41)&0x40)
dmaupload();
if (source&0x04)
{
if (!usesystimer&&!paused)
{
if (gtimerpos<=256)
gtimerpos=gtimerlen;
else
gtimerpos-=256;
settimer(0x00);
settimerlen((gtimerpos<=256)?(256-gtimerpos):0);
settimer(0x04);
if (gtimerpos==gtimerlen)
if (doublechan)
processtickdc();
else
processtick();
}
else
{
settimer(0x00);
settimer(0x04);
}
}
if (source&0x08)
{
settimer(0x00);
settimer(0x04);
}
if (source&0x60)
handle_voice();
}
}
static void timerrout()
{
if (paused)
return;
if (stimerpos<=65536)
stimerpos=stimerlen;
else
stimerpos-=65536;
tmSetNewRate((stimerpos<=65536)?stimerpos:65536);
if (stimerpos==stimerlen)
if (doublechan)
processtickdc();
else
processtick();
}
void stackcall(void *);
#pragma aux stackcall parm [eax] = \
"mov word ptr oldssesp+4,ss" \
"mov dword ptr oldssesp+0,esp" \
"lss esp,stack" \
"sti" \
"call eax" \
"cli" \
"lss esp,oldssesp"
static void stackirq()
{
if (stackused)
return;
stackused++;
stackcall(irqrout);
stackused--;
}
static void stacktimer()
{
if (stackused)
return;
stackused++;
stackcall(timerrout);
stackused--;
}
static void voidtimer()
{
}
static void calcvols(guschan &c)
{
short vl=(c.orgvol*mastervol/16)*amplify/65536;
if (vl>=0x200)
vl=0x1FF;
short vr=(vl*((c.orgpan*masterpan/64)+0x80))>>8;
vl-=vr;
if (masterbal)
if (masterbal<0)
vr=(vr*(64+masterbal))>>6;
else
vl=(vl*(64-masterbal))>>6;
c.voll=vl;
c.volr=vr;
}
static int LoadSamples(sampleinfo *sil, int n)
{
if (n>MAXSAMPLES)
return 0;
if (!mcpReduceSamples(sil, n, gusMem, mcpRedGUS))
return 0;
if (!doslowupload)
irqInit(gusIRQ, stackirq, 1);
mempos=0;
int i;
for (i=0; i<(2*n); i++)
{
sampleinfo &si=sil[i%n];
if ((!!(si.type&mcpSamp16Bit))^(i<n))
continue;
gussample &s=samples[i%n];
s.length=si.length;
s.loopstart=si.loopstart;
s.loopend=si.loopend;
s.samprate=si.samprate;
s.type=si.type;
int bit16=!!(si.type&mcpSamp16Bit);
s.redlev=(si.type&mcpSampRedRate4)?2:(si.type&mcpSampRedRate2)?1:0;
s.pos=mempos;
mempos+=(s.length+2)<<bit16;
if (s.loopstart==s.loopend)
s.type&=~mcpSampLoop;
dma16bit=bit16;
dmaleft=(s.length+2)<<dma16bit;
dmaxfer=si.ptr;
dmapos=s.pos;
if (doslowupload)
{
slowupload();
continue;
}
dmaupload();
unsigned long t0=clock();
while ((t0+(int)CLK_TCK*2)>clock())
if (!dmaactive)
break;
if (!dmaactive)
continue;
irqClose();
doslowupload=1;
dmaactive=0;
dma16bit=bit16;
dmaleft=(s.length+2)<<dma16bit;
dmaxfer=si.ptr;
dmapos=s.pos;
slowupload();
}
if (!doslowupload)
irqClose();
samplenum=n;
// smSamplesTo8(sil, n);
for (i=0; i<n; i++)
samples[i].ptr=sil[i].ptr;
return 1;
}
static int OpenPlayer(int chan, void (*proc)())
{
if (chan>32)
chan=32;
mixSetChan(chan);
orgspeed=50*256;
memset(channels, 0, sizeof(guschan)*chan);
playerproc=proc;
doublechan=chan<8;
int i;
if (doublechan)
{
initgus(2*chan);
for (i=0; i<chan; i++)
{
selvoc(2*i);
setpan(0);
selvoc(2*i+1);
setpan(15);
}
}
else
initgus(chan);
channelnum=chan;
selvoc(0);
delayGUS();
outpGUS0(0x09);
delayGUS();
if (usesystimer)
{
stimerlen=muldiv64(256, 1193046*256, orgspeed*relspeed);
stimerpos=stimerlen;
tmInit(stacktimer, (stimerpos<=65536)?stimerpos:65536);
}
else
{
irqInit(gusIRQ, stackirq, 1);
gtimerlen=muldiv64(256, 12500*256, orgspeed*relspeed);
gtimerpos=gtimerlen;
settimerlen((gtimerpos<=256)?(256-gtimerpos):0);
settimer(0x04);
tmInit(voidtimer, 65536);
}
outpGUS8(0x04);
outpGUS9(0x01);
mcpNChan=chan;
return 1;
}
static void ClosePlayer()
{
mcpNChan=0;
tmClose();
if (!usesystimer)
irqClose();
initgus(14);
channelnum=0;
}
unsigned short _disableint();
void _restoreint(unsigned short);
#pragma aux _disableint value [ax] = "pushf" "pop ax" "cli"
#pragma aux _restoreint parm [ax] = "push ax" "popf"
static void SetSpeed(unsigned long s)
{
orgspeed=s;
}
static void SetFilter(unsigned char f)
{
filter=f%8;
}
static void SetMasterVol(unsigned char vol)
{
mastervol=vol;
int i;
for (i=0; i<channelnum; i++)
calcvols(channels[i]);
}
static void SetMasterPan(signed char pan)
{
masterpan=pan;
int i;
for (i=0; i<channelnum; i++)
calcvols(channels[i]);
}
static void SetMasterBal(signed char bal)
{
masterbal=bal;
int i;
for (i=0; i<channelnum; i++)
calcvols(channels[i]);
}
static void SetMasterSpeed(unsigned short sp)
{
if (sp<16)
sp=16;
relspeed=sp;
}
static void SetMasterFreq(unsigned short p)
{
masterfreq=p;
}
static void SetAmplify(unsigned long amp)
{
amplify=amp;
int i;
for (i=0; i<channelnum; i++)
calcvols(channels[i]);
mixSetAmplify(amp);
}
static void SetInstr(unsigned char ch, unsigned short samp)
{
channels[ch].chstatus=1;
channels[ch].nextsample=samp;
channels[ch].loopchange=1;
channels[ch].inited=1;
}
static void GetMixChannel(int ch, mixchannel &chn, int rate)
{
chn.status=0;
unsigned short is=_disableint();
selvoc(doublechan?2*ch:ch);
unsigned long pos=getpoint8(0);
unsigned char mode=getmode();
_restoreint(is);
guschan &c=channels[ch];
if ((paused&&!c.wasplaying)||(!paused&&(mode&1))||!c.inited)
return;
if (c.pause)
chn.status|=MIX_MUTE;
unsigned short resvoll,resvolr;
resvoll=c.voll;
resvolr=c.volr;
chn.vols[0]=resvoll*4096/amplify;
chn.vols[1]=resvolr*4096/amplify;
chn.status|=((mode&0x08)?MIX_LOOPED:0)|((mode&0x10)?MIX_PINGPONGLOOP:0)|((mode&0x04)?MIX_PLAY16BIT:0);
chn.step=muldiv64(muldiv64(muldiv64(c.orgfreq, masterfreq, 256), c.samprate, c.orgdiv), 1<<16, rate);
if (mode&0x40)
chn.step=-chn.step;
chn.samp=c.smpptr;
chn.length=c.endpos-c.startpos;
chn.loopstart=c.loopstart-c.startpos;
chn.loopend=c.loopend-c.startpos;
chn.fpos=pos<<7;
chn.pos=((pos>>9)&0xFFFFF)-c.startpos;
if (filter>=6)
chn.status|=MIX_INTERPOLATE;
chn.status|=MIX_PLAYING;
}
static void SetVolume(unsigned char ch, signed short v)
{
if (v>=0x100)
v=0x100;
if (v<0)
v=0;
channels[ch].orgvol=v;
calcvols(channels[ch]);
}
static void SetPan(unsigned char ch, signed short p)
{
if (p>=0x80)
p=0x80;
if (p<=-0x80)
p=-0x80;
channels[ch].orgpan=p;
calcvols(channels[ch]);
}
static void SetReverbChorus(unsigned char ch, unsigned char reverb, unsigned char chorus)
{
}
static void SetPos(unsigned char ch, unsigned long pos)
{
channels[ch].nextpos=pos;
}
static void SetFreq(unsigned char ch, unsigned long frq, unsigned long div)
{
channels[ch].orgfreq=frq;
channels[ch].orgdiv=div;
}
static void SetFreqLog(unsigned char ch, signed short note)
{
channels[ch].orgfreq=8363;
channels[ch].orgdiv=mcpGetFreq8363(-note);
}
static void Play(unsigned char ch, unsigned long frq, unsigned long div)
{
channels[ch].orgfreq=frq;
channels[ch].orgdiv=div;
channels[ch].nextpos=0;
channels[ch].loopchange=1;
}
static void PlayLog(unsigned char ch, signed short note)
{
Play(ch, 8363, mcpGetFreq8363(-note));
}
static void Stop(unsigned char ch)
{
channels[ch].nextpos=-1;
channels[ch].chstatus=1;
}
static void LeaveLoop(unsigned char ch)
{
channels[ch].loopchange=0;
}
static void Reset(unsigned char ch)
{
unsigned char p=channels[ch].pause;
memset(channels+ch, 0, sizeof(guschan));
channels[ch].pause=p;
}
static void Pause(unsigned char p)
{
if (p==paused)
return;
int i;
if (paused)
{
for (i=0; i<channelnum; i++)
if (doublechan)
{
if (channels[i].wasplaying)
{
selvoc(2*i);
setmode(channels[i].mode|(getmode()&0x40));
selvoc(2*i+1);
setmode(channels[i].mode|(getmode()&0x40));
}
}
else
if (channels[i].wasplaying)
{
selvoc(i);
setmode(channels[i].mode|(getmode()&0x40));
}
gtimerpos=0;
stimerpos=0;
paused=0;
if (!usesystimer)
settimer(0x04);
}
else
{
paused=1;
if (!usesystimer)
settimer(0x00);
for (i=0; i<channelnum; i++)
if (doublechan)
{
selvoc(2*i);
channels[i].wasplaying=!(getmode()&1);
setmode(3|(getmode()&0x40));
selvoc(2*i+1);
setmode(3|(getmode()&0x40));
}
else
{
selvoc(i);
channels[i].wasplaying=!(getmode()&1);
setmode(3|(getmode()&0x40));
}
}
}
static int GetStatus(int ch)
{
unsigned is=_disableint();
selvoc(doublechan?2*ch:ch);
int rv=!(getmode()&1);
if (paused&&channels[ch].wasplaying)
rv=1;
_restoreint(is);
return rv;
}
static void SET(int ch, int opt, int val)
{
switch (opt)
{
case mcpGSpeed:
SetSpeed(val);
break;
case mcpCInstrument:
SetInstr(ch, val);
break;
case mcpCMute:
channels[ch].pause=val;
break;
case mcpCStatus:
if (!val)
Stop(ch);
break;
case mcpCReset:
Reset(ch);
break;
case mcpCVolume:
SetVolume(ch, val);
break;
case mcpCPanning:
SetPan(ch, val);
break;
case mcpMasterAmplify:
SetAmplify(val);
break;
case mcpMasterPause:
Pause(val);
break;
case mcpCPosition:
SetPos(ch, val);
break;
case mcpCPitch:
SetFreqLog(ch, val);
break;
case mcpCPitchFix:
SetFreq(ch, val, 0x10000);
break;
case mcpCPitch6848:
SetFreq(ch, 6848, val);
break;
case mcpMasterVolume:
SetMasterVol(val);
break;
case mcpMasterPanning:
SetMasterPan(val);
break;
case mcpMasterBalance:
SetMasterBal(val);
break;
case mcpMasterSpeed:
SetMasterSpeed(val);
break;
case mcpMasterPitch:
SetMasterFreq(val);
break;
case mcpMasterFilter:
SetFilter(val);
break;
}
}
static int GET(int ch, int opt)
{
switch (opt)
{
case mcpCStatus:
return !!GetStatus(ch);
case mcpCMute:
return !!channels[ch].pause;
case mcpGTimer:
return tmGetTimer();
}
return 0;
}
static int initu(const deviceinfo &c)
{
doslowupload=(c.opt&SS_GUS_SLOWUPLOAD)||(c.dma==-1)||(c.irq==-1);
usesystimer=(c.opt&SS_GUS_SYSTIMER)||(c.irq==-1);
dmaactive=0;
dmalen=32768;
dmabuf=dmaAlloc(dmalen, dmasel);
dmalen&=~31;
stack=new char [stacksize];
if (!stack||!dmabuf)
return 0;
stack+=stacksize;
stackused=0;
if (!mixInit(GetMixChannel, 1))
return 0;
int i;
if (!testPort(c.port))
return 0;
gusPort=c.port;
gusIRQ=c.irq;
gusDMA=c.dma;
// gusIRQ2=c.irq2;
gusDMA2=c.dma2;
channelnum=0;
filter=0;
initgus(14);
relspeed=256;
paused=0;
mastervol=64;
masterpan=64;
masterbal=0;
masterfreq=256;
amplify=65536;
linvol[0]=0;
linvol[512]=0x0FFF;
for (i=1; i<512; i++)
{
int j,k;
k=i;
for (j=0x0600; k; j+=0x0100)
k>>=1;
linvol[i]=j|((i<<(8-((j-0x700)>>8)))&0xFF);
}
mcpLoadSamples=LoadSamples;
mcpOpenPlayer=OpenPlayer;
mcpClosePlayer=ClosePlayer;
mcpSet=SET;
mcpGet=GET;
return 1;
}
static void closeu()
{
mcpOpenPlayer=0;
mixClose();
dmaFree(dmasel);
delete (char near *)(stack-stacksize);
}
static int detectu(deviceinfo &c)
{
if (!getcfg())
{
if (c.port==-1)
return 0;
gusPort=c.port;
gusIRQ=c.irq;
// gusIRQ2=(c.irq2==-1)?c.irq:c.irq2;
gusDMA=c.dma;
gusDMA2=(c.dma2==-1)?c.dma:c.dma2;
}
else
{
if (c.port!=-1)
gusPort=c.port;
if (c.irq!=-1)
gusIRQ=c.irq;
// if (c.irq2!=-1)
// gusIRQ2=c.irq2;
if (c.dma!=-1)
gusDMA=c.dma;
if (c.dma2!=-1)
gusDMA2=c.dma2;
}
if (!testPort(gusPort))
return 0;
c.subtype=-1;
c.dev=&mcpUltraSound;
c.port=gusPort;
c.port2=-1;
// c.irq=(gusIRQ<gusIRQ2)?gusIRQ:gusIRQ2;
// c.irq2=(gusIRQ<gusIRQ2)?gusIRQ2:gusIRQ;
c.irq=gusIRQ;
// c.irq2=gusIRQ2;
c.irq2=-1;
c.dma=gusDMA;
c.dma2=gusDMA2;
if ((c.opt&SS_GUS_SLOWUPLOAD)&&(c.opt&SS_GUS_SYSTIMER))
c.irq=-1;
if ((c.opt&SS_GUS_SLOWUPLOAD)||(c.irq==-1))
{
c.dma=-1;
c.dma2=-1;
}
c.mem=gusMem;
c.chan=32;
return 1;
}
extern "C" sounddevice mcpUltraSound={SS_WAVETABLE, "Gravis UltraSound", detectu, initu, closeu};
#include "devigen.h"
#include "psetting.h"
static unsigned long gusGetOpt(const char *sec)
{
unsigned long opt=0;
if (cfGetProfileBool(sec, "gusslowupload", 1, 1))
opt|=SS_GUS_SLOWUPLOAD;
if (cfGetProfileBool(sec, "gussystemtimer", 1, 1))
opt|=SS_GUS_SYSTIMER;
return opt;
}
extern "C" devaddstruct mcpGUSAdd = {gusGetOpt, 0, 0, 0};